#ifndef BEZIER_H
#define BEZIER_H

#include <cassert>
#include <algorithm>
#include <vector>

#include <QPointF>
#include <QtOpenGL/QtOpenGL>

#include "tcurve.h"

using std::vector;

template< class IPoint >
class Bezier : public TCurve< IPoint >
{
public:

    /* Metody. */
    void AddPoint( const IPoint& point );
    void AddPoint( const IPoint& point, int point_index );

    void RemovePoint( );
    void RemovePoint( int point_index );

    IPoint Eval( double t ) const;
    IPoint* ComputePoints( int n ) const;

private:
    /* Pola. */
    int degree; // Stopien krzywej Beziera.
};

template< class IPoint >
void Bezier< IPoint >::AddPoint( const IPoint& point )
{
    TCurve< IPoint >::AddPoint( point );
    degree++;
}

template< class IPoint >
void Bezier< IPoint >::AddPoint( const IPoint& point, int point_index )
{
    TCurve< IPoint >::AddPoint( point, point_index );
    degree++;
}

template< class IPoint >
void Bezier< IPoint >::RemovePoint( )
{
    TCurve< IPoint >::RemovePoint( );
    degree--;
}

template< class IPoint >
void Bezier< IPoint >::RemovePoint( int point_index )
{
    TCurve< IPoint >::RemovePoint( point_index );
    degree--;
}

template< class IPoint >
IPoint Bezier< IPoint >::Eval( double t ) const
{
    assert( 0.0 <= t && t <= 1.0 );

    IPoint P[degree + 1];

    for ( int i = 0; i <= degree; i++ )
        P[i] = control_points[i];

    for ( int k = 1; k <= degree; k++ )
        for ( int i = 0; i <= degree - k; i++ )
            P[i] = ( 1.0 - t ) * P[i] + t * P[i + 1];

    return P[0];
}

template< class IPoint >
IPoint* Bezier< IPoint >::ComputePoints( int n ) const
{
    vector< IPoint > points( n );

    for ( int i = 0; i < n; i++ )
        points[i] = Eval( static_cast<double>( i ) / ( n - 1 ) );

    return points;
}

#endif // BEZIER_H
